#项目实训
"""
1、下面程序的功能是：验证四方定理，即所有自然数至多只需四个数的平方和就可以表示，请找出错误并修改验证。
四方定理指出：任何自然数都可以表示为最多4个整数的平方和
比如：
5 = 1² + 2²
7 = 1² + 1² + 1² + 2²
20 = 2² + 4² 或 1² + 1² + 3² + 3²
"""


# 错误代码
# def sum_square(n):
#     for i in range(1, n / 2 + 1):
#         for j in range(1, i + 1):
#             for k in range(1, i + 1):
#                 for l in range(1, i + 1):
#                     if n == i * i + j * j + k * k + 1 * 1:
#                         print(n, '=', i, '*', i, '+', j, '*', j, '+', k, '*', k, '+', 1, '*', 1)
#
#
# sum_square(20)

# 正确代码
def sum_squre(n):
    for i in range(1, n // 2 + 1):
        for j in range(1, i + 1): #
            for k in range(1, i + 1):
                for l in range(1, i + 1):
                    if n == i * i + j * j + k * k + l * l:
                        print(n, '=', i, '*', i, '+', j, '*', j, '+',
                              k, '*', k, '+', l, '*', l)


sum_squre(20)



"""
2、下面程序的功能是：解决买水问题，输入钱数，输出可买水的瓶数。规则如下：1元钱可以买1瓶水，2个空瓶可以换1瓶水，3个瓶盖也可以换1瓶水。请找出错误并修改验证。
"""
# 错误代码
# Water = int(input('请输入钱数：'))
# # 定义买水的函数，nW 表示新水的数量，nB 表示新瓶的数量，nL 表示新盖的数量
# def f(nW, nB, nL):
#     global Water, bottle, lid
#     bottle = nB + nW
#     lid = nL + nW
#     nW = bottle // 2 + lid
#     Water += nW
#     bottle = bottle %
#     lid = lid % 3
#     if (nB < 2 or nL < 3 or nW < 1):
#         return
#     else:
#         f(nW, nB, nL)
# f(Water, 0, 0)
# print(Water)
# 正确代码
Water = int(input('请输入钱数：'))
# 定义买水的函数，nW 表示新水的数量，nB 表示新瓶的数量，nL 表示新盖的数量
def f(nW, nB, nL):
    global Water, bottle, lid
    bottle = nB + nW
    lid = nL + nW
    nW = bottle // 2 + lid // 3
    Water += nW
    nB = bottle % 2
    nL = lid % 3
    if (nB < 2 and nL < 3 and nW < 1):
        return
    else:
        f(nW, nB, nL)
f(Water, 0, 0)
print(Water)
"""
以3瓶为例：
第一轮兑换：
空瓶：3÷2=1瓶水（余1空瓶）
瓶盖：3÷3=1瓶水（余0瓶盖）
共换得2瓶水
喝完后：1+2=3个空瓶 + 0+2=2个瓶盖
累计：3+2=5瓶

第二轮兑换：
空瓶：3÷2=1瓶水（余1空瓶）
瓶盖：2÷3=0瓶水（余2瓶盖）
共换得1瓶水
喝完后：1+1=2个空瓶 + 2+1=3个瓶盖
累计：5+1=6瓶

第三轮兑换：
空瓶：2÷2=1瓶水（余0空瓶）
瓶盖：3÷3=1瓶水（余0瓶盖）
共换得2瓶水
喝完后：0+2=2个空瓶 + 0+2=2个瓶盖
累计：6+2=8瓶

第四轮兑换：
空瓶：2÷2=1瓶水（余0空瓶）
瓶盖：2÷3=0瓶水（余2瓶盖）
共换得1瓶水
喝完后：0+1=1个空瓶 + 2+1=3个瓶盖
累计：8+1=9瓶

第五轮兑换：
空瓶：1÷2=0瓶水（余1空瓶）
瓶盖：3÷3=1瓶水（余0瓶盖）
共换得1瓶水
喝完后：1+1=2个空瓶 + 0+1=1个瓶盖
累计：9+1=10瓶

第六轮兑换：
空瓶：2÷2=1瓶水（余0空瓶）
瓶盖：1÷3=0瓶水（余1瓶盖）
共换得1瓶水
喝完后：0+1=1个空瓶 + 1+1=2个瓶盖
累计：10+1=11瓶
"""
"""
下面程序的功能是：设计一个函数，判断传入的整数列表（要求元素个数大于2）中的元素能否构成等差数列（从第二项起，每一项与它的前一项的差等于同一个常数），如果能，返回“构成等差数列”，否则返回“不能构成等差数列”。请将正确答案写在横线处。

小提示：eval（）函数用于执行一个字符串表达式，并返回表达式的值。例如, eval（'[1,2,3,4]'）的结果为列表[1,2,3,4].

def Isf(list_number):
    d = _______              							#求公差d
    for i in range(1, len(list_number) - 1):
        if _______:
            return '构成等差数列'
        else:
            return '不能构成等差数列'
list = eval(input('请输入一个整数数列（元素个数大于2）：'))
print('此数列', _______)

"""


def Isf(list_number):
    d = list_number[1] - list_number[0]  # 求公差d
    for i in range(1, len(list_number) - 1):
        if d == list_number[i + 1] - list_number[i]:
            return '构成等差数列'
        else:
            return '不能构成等差数列'


list = eval(input('请输入一个整数数列（元素个数大于2）：'))
print('此数列', Isf(list))

"""
一般来说，正常的邮件中不会出现太多类似于【、】、*、\、/、+、-这样的符号，如果一封邮件中包含的类似字符数量超过一定的比例，可以直接认为它是垃圾邮件。下面程序的功能是：根据给定的邮件内容进行分类，提示“垃圾邮件”或“正常邮件”。请将正确答案写在横线处

def check(text, rate=0.2):
    characters = '【】*-/\\'
    num = 0
    for ch in characters:
        if ch in text:
            _______
    if _______:
        return '垃圾邮件'
    return '正常邮件'
text = '我公【司免【开发】票微-信同*号'
print(_______)
"""
def check(text, rate=0.2):
    characters = '【】*-/\\'
    num = 0
    for ch in characters:
        if ch in text:
            num += num + text.count(ch)
    if num / len(text) > rate:
        return '垃圾邮件'
    return '正常邮件'
text = '我公【司免【开发】票微-信同*号'
print(check(text))
"""
编写函数，接收两个正整数作为参数，返回一个元组，其中第一个元素为两个正整数的最大公约数，第二个元素为其最小公倍数，输出最大公约数和最小公倍数。
"""
def demo(m, n):
    p = m * n
    while m % n != 0:
        m, n = n, m % n
    return n, p // n
a = int(input('请输入其中一个整数：'))
b = int(input('请输入另一个整数：'))
c = demo(a, b)
print('{}和{}的最大公约数为{}'.format(a, b, c[0]))
print('{}和{}的最小公倍数为{}'.format(a, b, c[1]))
"""
核心算法：辗转相除法
辗转相除法的原理：两个数的最大公约数等于其中较小的数和两数相除余数的最大公约数。

以12 和 18 为例
初始状态：
m = 12, n = 18
p = m × n = 12 × 18 = 216（保存乘积用于计算最小公倍数）

第一次循环：
条件：m % n = 12 % 18 = 12 ≠ 0（进入循环）
执行：m, n = n, m % n → m=18, n=12

第二次循环：
条件：m % n = 18 % 12 = 6 ≠ 0（进入循环）
执行：m, n = n, m % n → m=12, n=6

第三次循环：
条件：m % n = 12 % 6 = 0（退出循环）

返回结果：
最大公约数 = n = 6
最小公倍数 = p ÷ n = 216 ÷ 6 = 36
"""
"""
编写函数，求三个数中最大值。
"""
def getMax(num1,num2,num3):
    if num1 > num2:
        temp = num1
    else:
        temp = num2
    if temp > num3:
        return "其中最大值为：" + str(temp)
    else:
        return "其中最大值为：" + str(num3)

a = int(input('请输入第1个整数：'))
b = int(input('请输入第2个整数：'))
c = int(input('请输入第3个整数：'))
maxValue = getMax(a, b, c)
print(maxValue)

"""
用递归方法计算S=1+2+3+…+n.
"""
def f(n):
    if n == 1:
        return 1
    else:
        return f(n - 1) + n
n = int(input('请输入一个正整数：'))
print('S=1+2+3+…+n:',f(n))
"""
哥德巴赫猜想：每个不小于 6 的偶数都是两个奇素数之和。编写程序，验证哥德巴赫猜想对20以内的正偶数成立。
"""
def prime(i):							#定义函数，判断i是否为素数
    if i <= 1:						#如果小于等于1，返回0（i不是素数）
        return 0
    if i == 2:						#如果等于2，返回1（i是素数）
        return 1
    for j in range(2, i):			#判断i是否为素数
        if i % j == 0:				#i可以被j除尽，余数为0
            return 0					#返回0，i不是素数
        elif i != j + 1:				#如果i不等于j+1，继续
            continue
        else:
            return 1					#否则，i等于j+1，返回1（i是素数）
n = 0
for i in range(6, 21, 2):
    k = 2
    while k <= i/2:
        j = i - k
        flag1 = prime(k)				#调用prime函数
        if flag1:						#如果k为素数
            flag2 = prime(j)			#调用prime函数
            if flag2:					#如果k和j都是素数
                print(i, '=', k, '+', j)		#输出结果
                n += 1
        k = k + 1
"""
素数就是大于1的自然数，而且它只有1和它自己本身这两个因数
第一步：i = 8
k从2开始，检查到4（因为8/2=4）

第一次循环：k = 2
j = 8 - 2 = 6
prime(2) = 1（2是素数）
prime(6) = 0（6不是素数）
不满足条件，继续

第二次循环：k = 3
j = 8 - 3 = 5
prime(3) = 1（3是素数）
prime(5) = 1（5是素数）
满足条件，输出：8 = 3 + 5

第三次循环：k = 4
j = 8 - 4 = 4
prime(4) = 0（4不是素数）
不满足条件，结束
完整验证结果
程序会依次验证6到20的所有偶数：
6 = 3 + 3
8 = 3 + 5
10 = 3 + 7 或 5 + 5
12 = 5 + 7
14 = 3 + 11 或 7 + 7
16 = 3 + 13 或 5 + 11
18 = 5 + 13 或 7 + 11
20 = 3 + 17 或 7 + 13
"""


#项目考核
"""
1、下面关于函数的说法，错误的是（ C ）。
A.在不同函数中可以使用相同名字的变量
B.函数可以减少代码的重复，使程序更加模块化
C.调用函数时，传入参数的顺序和函数定义时的顺序必须不同
D.函数体中如果没有return语句，函数返回空值None

2、使用（C）关键字创建自定义函数。
A. function
B. func
C. def
D. procedure

3、使用（A）关键字定义匿名函数。
A. lambda
B. main
C. function
D. def

4、在Python中，函数（D）。
A.不可以嵌套定义
B.不可以嵌套调用
C.不可以递归调用
D.以上都不对

5、下面说法正确的是（B）。
A.函数的名称可以随意命名
B.带有默认值的参数一定位于参数列表的末尾
C.局部变量的作用域是整个程序
D.函数定义后，系统会自动执行其内的代码

6、执行下面程序，输出结果为（D）。
def f（）:
    print(x)
    x = 20+1
f（）
A. 0	B. 20	C. 21	D.程序出现异常

7、下面关键字中，用于导入模块的是（C）。
A. include
B. from
C. import
D. del

8、关于 name 的说法，下面描述错误的是（A）。
A.它是Python提供的一个方法
B.每个模块内部都有一个 name 属性
C.当它的值为“ main ”时，表示模块自身在运行
D.当它的值不为“ main ”时，表示模块被引用
"""

"""
(1)函数可以有多个参数，参数之间使用_逗号_隔开。
(2)使用_return_语句可以返回函数值并退出函数。
(3)函数能处理比定义时更多的参数，它们是_不定长_参数。
(4)在函数中调用另一个函数，这就是函数的_嵌套_调用。
(5)在函数内定义的变量称为_局部_变量。
(6)如果想在函数中修改全局变量，需要在变量前加上_global_关键字。

(7)下面程序的运行结果是_7，5_。
a = 3
b = 4
def fun(x, y):
    b=5
    print(x + y, b)
fun(a, b)

(8)下面程序的运行结果是_5,4_。
def fun(x):
    a = 3
    a += x
    return(a)
k = 2
m = 1
n = fun(k)
m = fun(m)
print(n, m)

(9)下面程序的运行结果是_1,3,4_。
def fun(x, y):
    global b
    b = 3
    c = a + b
    return c
a = 1
b = 2
c = fun(a, b)
print(a, b, c)

(10)下面程序的运行结果是_1_。
def outer():
    a = 1
    def inner():
        nonlocal a
        a = 2
    inner()
    print(a)
outer()
"""

"""
编写函数，实现将十进制数转换为二进制数。
"""
def dec2bin(num):
    l = []
    if num < 0:
        return '-' + dec2bin(abs(num))  # 如果是负数，先处理其绝对值，然后加上负号
    while True:
        num, remainder = divmod(num, 2)  # 除以2，得到商和余数
        l.append(str(remainder))
        if num == 0:
            return ''.join(l[::-1])
"""
第1次循环：10 ÷ 2 = 5 余 0 → l = ['0']
第2次循环：5 ÷ 2 = 2 余 1 → l = ['0', '1']  
第3次循环：2 ÷ 2 = 1 余 0 → l = ['0', '1', '0']
第4次循环：1 ÷ 2 = 0 余 1 → l = ['0', '1', '0', '1']

反转列表：['1', '0', '1', '0'] → 连接成字符串："1010"
"""
"""
用二分法查找升序排序的100个随机整数(1~100)数列中某个数并输出其位置。

提示：二分法是一种快速查找的方法，时间复杂度低，逻辑简单易懂，就是不断地找出中间值，用中间值对比查找的值；若中间值大，则继续在左侧查找；若中间值小，则继续在右侧查找。
"""
import random


def random_100(amout):
    li = []
    for i in range(amout):
        s = random.randint(0, amout)
        li.append(s)
    return li


lst = sorted(random_100(100))
print(lst)


# 定义函数
def func(n, lst, left=0, right=None):
    if right == None:
        right = len(lst) - 1
    if left < right:
        mid = (left + right) // 2
        if n < lst[mid]:
            right = mid - 1
        elif n > lst[mid]:
            left = mid + 1
        else:
            print('你输入的数在这个列表中,它的位置{}\n'.format(mid))
            return True
            return func(n, lst, left, right)
    else:
        print('你输入的数不在这个列表中\n')
        return False
while True:
    n = int(input('请输入你要查找的数:'))
    func(n, lst)


"""
根据输入的边数和边长，利用 turtle 库绘制正多边形。

forward(distance)：沿当前方向移动指定距离（像素），方向由旋转角度决定。
goto(x, y)：直接移动到指定的绝对坐标点，不改变方向。
"""
import turtle as t
def polygon(n, length): #绘制正n边形，边长为length
    for i in range(n):  #循环n次
        t.forward(length)  #前进length
        t.left(360/n)     #左转角度为正n边形的外角

n = int(input('请输入边数：'))
length = int(input('请输入边长：'))
polygon(n, length)
t.done()

"""
输入 a(0 < a⩽9) 和 n 的值，计算 s=a+aa+aaa+....+aa....a(n个a) 的值。

5 + 55 + 555 + 5555 ....
"""
def sum_A(a,n):
    result,t = 0,0
    for i in range(n):
        t = t * 10 + a
        result += t
    return result
a = int(input('输入整数a的值:'))
n = int(input('输入整数n的值:'))
print(sum_A(a, n))